import asyncio
from scapy.all import sr1, send, IP, TCP
import logging

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 异步函数：扫描单个端口
async def scan_port(ip, port):
    try:
        # 构造SYN包
        syn_packet = IP(dst=ip) / TCP(dport=port, flags='S')
        
        # 使用sr1发送包并等待响应，设置超时时间为1秒
        response = await asyncio.get_running_loop().run_in_executor(None, lambda: sr1(syn_packet, timeout=0.025, verbose=0))
        #reader, writer = await asyncio.wait_for(asyncio.open_connection(ip, port), timeout=0.025)
        
        if response is not None and TCP in response:
            tcp_layer = response.getlayer(TCP)
            if tcp_layer.flags == 'SA':  # SYN-ACK
                return {"port": port, "status": "open"}
            else:
                return {"port": port, "status": "closed"}
        else:
            return {"port": port, "status": "no response"}
    except Exception as e:
        logging.error(f"Error scanning port {port}: {e}")
        return {"port": port, "status": f"error: {str(e)}"}

# 异步函数：扫描多个端口
async def scan_ports(ip, port_range):
    open_ports = []
    
    # 根据输入类型处理不同的端口范围
    if isinstance(port_range, int):  # 单个端口号
        ports_to_scan = [port_range]
    elif isinstance(port_range, range):  # 端口范围
        ports_to_scan = list(port_range)
    elif isinstance(port_range, (list, tuple)):  # 端口列表或元组
        ports_to_scan = list(port_range)
    else:
        raise ValueError("Invalid port range type. Expected int, range, list, or tuple.")
    
    # 创建并发任务
    tasks = [asyncio.create_task(scan_port(ip, port)) for port in ports_to_scan]
    # tasks = [check_port(ip, port) for port in ports_to_scan]
    # 等待所有任务完成，并收集结果
    results = await asyncio.gather(*tasks)
    
    for result in results:
        if result is None:  # 检查是否为 None
            logging.warning(f"No result for an unknown port.")
            continue
        
        if result['status'] == 'open':
            open_ports.append(result['port'])

    
    return open_ports

# 主函数
if __name__ == "__main__":
    ip = "192.168.34.227"
    port_range = [445, 3389, 8080, 1134, 2256, 8899, 1024]  # 端口范围

    # 启动异步事件循环并获取扫描结果
    try:
        open_ports = asyncio.run(scan_ports(ip, port_range))

        # 处理扫描结果
        if open_ports:
            open_ports_str = ', '.join(str(p) for p in open_ports)
            print(f"Open ports on {ip}: {open_ports_str}")
        else:
            print(f"No open ports found on {ip}.")
    except Exception as e:
        logging.error(f"An error occurred during the scan: {e}")